home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / src / text.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-05-30  |  22.5 KB  |  657 lines

  1. /********************************************************************\
  2.  * text.c -- a basic text field                                     *
  3.  * Copyright (C) 1997 Robin D. Clark                                *
  4.  *                                                                  *
  5.  * This program is free software; you can redistribute it and/or    *
  6.  * modify it under the terms of the GNU General Public License as   *
  7.  * published by the Free Software Foundation; either version 2 of   *
  8.  * the License, or (at your option) any later version.              *
  9.  *                                                                  *
  10.  * This program is distributed in the hope that it will be useful,  *
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
  13.  * GNU General Public License for more details.                     *
  14.  *                                                                  *
  15.  * You should have received a copy of the GNU General Public License*
  16.  * along with this program; if not, write to the Free Software      *
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.        *
  18.  *                                                                  *
  19.  *   Author: Rob Clark                                              *
  20.  * Internet: rclark@cs.hmc.edu                                      *
  21.  *  Address: 609 8th Street                                         *
  22.  *           Huntington Beach, CA 92648-4632                        *
  23. \********************************************************************/
  24.  
  25. #include "wconfig.h"
  26.  
  27. #include <X11/Xlib.h>
  28. #include <X11/Xutil.h>
  29. #include <X11/keysym.h>
  30. #include <stdlib.h>
  31. #include <ctype.h>
  32.  
  33. #include "WindowMaker.h"
  34. #include "funcs.h"
  35. #include "text.h"
  36. #include "actions.h"
  37.  
  38. /* X11R5 don't have this */
  39. #ifndef IsPrivateKeypadKey
  40. #define IsPrivateKeypadKey(keysym) \
  41.   (((KeySym)(keysym) >= 0x11000000) && ((KeySym)(keysym) <= 0x1100FFFF))
  42. #endif
  43.  
  44.  
  45. #if 0
  46. #  define  ENTER(X)  fprintf(stderr,"Entering:  %s()\n", X);
  47. #  define  LEAVE(X)  fprintf(stderr,"Leaving:   %s()\n", X);
  48. #  define  DEBUG(X)  fprintf(stderr,"debug:     %s()\n", X);
  49. #else
  50. #  define  ENTER(X)
  51. #  define  LEAVE(X)
  52. #  define  DEBUG(X)
  53. #endif
  54.  
  55. extern Cursor wCursor[WCUR_LAST];
  56.  
  57. /********************************************************************\
  58.  * The event handler for the text-field:                            *
  59. \********************************************************************/
  60. static void textEventHandler( WObjDescriptor *desc, XEvent *event );
  61.  
  62. static void handleExpose( WObjDescriptor *desc, XEvent *event );
  63.  
  64. static void textInsert( WTextInput *wtext, char *txt );
  65. #if 0
  66. static void blink(void *data);
  67. #endif
  68.  
  69. /********************************************************************\
  70.  * handleKeyPress                                                   *
  71.  *   handle cursor keys, regular keys, etc.  Inserts characters in  *
  72.  *   text field, at cursor position, if it is a "Normal" key.  If   *
  73.  *   ksym is the delete key, backspace key, etc., the appropriate   *
  74.  *   action is performed on the text in the text field.  Does not   *
  75.  *   refresh the text field                                         *
  76.  *                                                                  *
  77.  * Args:   wText - the text field                                   *
  78.  *         ksym  - the key that was pressed                         *
  79.  * Return: True, unless the ksym is ignored                         *
  80.  * Global: modifier - the bitfield that keeps track of the modifier *
  81.  *                    keys that are down                            *
  82. \********************************************************************/
  83. static int
  84. handleKeyPress( WTextInput *wtext, XKeyEvent *event )
  85.   {      
  86.   KeySym ksym;
  87.   char buffer[32];
  88.   int count;
  89.  
  90.   count = XLookupString(event, buffer, 32, &ksym, NULL);
  91.  
  92.   /* Ignore these keys: */
  93.   if( IsFunctionKey(ksym)      || IsKeypadKey(ksym) ||
  94.       IsMiscFunctionKey(ksym)  || IsPFKey(ksym)     ||
  95.       IsPrivateKeypadKey(ksym) )
  96.     /* If we don't handle it, make sure it isn't a key that
  97.      * the window manager needs to see */
  98.     return False;
  99.   
  100.   /* Take care of the cursor keys.. ignore up and down
  101.    * cursor keys */
  102.   else if( IsCursorKey(ksym) )
  103.     {
  104.     int length = wtext->text.length;
  105.     switch(ksym)
  106.       {
  107.       case XK_Home:
  108.       case XK_Begin:
  109.       wtext->text.endPos = 0;
  110.       break;
  111.       case XK_Left:
  112.       wtext->text.endPos--;
  113.       break;
  114.       case XK_Right:
  115.       wtext->text.endPos++;
  116.       break;
  117.       case XK_End:
  118.       wtext->text.endPos = length;
  119.       break;
  120.       default:
  121.       return False;
  122.       }
  123.     /* make sure that the startPos and endPos have values
  124.      * that make sense  (ie the are in [0..length] ) */
  125.     if( wtext->text.endPos < 0 )
  126.       wtext->text.endPos = 0;
  127.     if( wtext->text.endPos > length )
  128.       wtext->text.endPos = length;
  129.     wtext->text.startPos = wtext->text.endPos;
  130.     }  
  131.   else
  132.     {
  133.     switch(ksym)
  134.       {
  135.       /* Ignore these keys: */
  136.       case XK_Escape:
  137.       wtext->canceled = True;
  138.       case XK_Return:
  139.       wtext->done = True;
  140.           break;
  141.       case XK_Tab:
  142.       case XK_Num_Lock:
  143.       break;
  144.       
  145.       case XK_Delete:
  146.       /* delete after cursor */
  147.       if( (wtext->text.endPos == wtext->text.startPos) && 
  148.           (wtext->text.endPos < wtext->text.length) )
  149.         wtext->text.endPos++;
  150.       textInsert( wtext, "" );
  151.       break;
  152.       case XK_BackSpace:
  153.       /* delete before cursor */
  154.       if(  (wtext->text.endPos == wtext->text.startPos) && 
  155.            (wtext->text.startPos > 0) )
  156.         wtext->text.startPos--;
  157.       textInsert( wtext, "" );
  158.       break;
  159.       default: 
  160.       if (count==1 && !iscntrl(buffer[0])) {
  161.           buffer[count] = 0;
  162.           textInsert( wtext, buffer);
  163.       }
  164.       }
  165.     }  
  166.   return True;
  167.   }
  168.  
  169.  
  170.  
  171. /********************************************************************\
  172.  * textXYtoPos                                                     *
  173.  *   given X coord, return position in array                        *
  174. \********************************************************************/
  175. static int
  176. textXtoPos( WTextInput *wtext, int x )
  177.   {
  178.   int pos;
  179.   x -= wtext->xOffset;
  180.   
  181.   for( pos=0; wtext->text.txt[pos] != '\0'; pos++ )
  182.     {
  183.     if( x < 0 )
  184.       break;
  185.     else
  186.       x -= WMWidthOfString( wtext->font, &(wtext->text.txt[pos]), 1 );
  187.     }
  188.   
  189.   return pos;
  190.   }
  191.  
  192. /********************************************************************\
  193.  * wTextCreate                                                      *
  194.  *   create an instance of a text class                             *
  195.  *                                                                  *
  196.  * Args:                                                            *
  197.  * Return:                                                          *
  198.  * Global: dpy - the display                                        *
  199. \********************************************************************/
  200. WTextInput *
  201. wTextCreate( WCoreWindow *core, int x, int y, int width, int height )
  202.   {
  203.   WTextInput *wtext;
  204.  
  205.   ENTER("wTextCreate");
  206.  
  207.   wtext = wmalloc(sizeof(WTextInput));
  208.   wtext->core = wCoreCreate( core, x, y, width, height );
  209.   wtext->core->descriptor.handle_anything = &textEventHandler; 
  210.   wtext->core->descriptor.handle_expose = &handleExpose;     
  211.   wtext->core->descriptor.parent_type = WCLASS_TEXT_INPUT;
  212.   wtext->core->descriptor.parent = wtext;
  213.  
  214.   wtext->font = core->screen_ptr->menu_entry_font;
  215.  
  216.   XDefineCursor( dpy, wtext->core->window, wCursor[WCUR_TEXT] );
  217.  
  218.   /* setup the text: */
  219.   wtext->text.txt      = (char *)wmalloc(sizeof(char));
  220.   wtext->text.txt[0]   = '\0';
  221.   wtext->text.length   = 0;
  222.   wtext->text.startPos = 0;
  223.   wtext->text.endPos   = 0;
  224.  
  225.     {
  226.     XGCValues gcv;
  227.  
  228.     gcv.foreground = core->screen_ptr->black_pixel;
  229.     gcv.background = core->screen_ptr->white_pixel;
  230.     gcv.line_width = 1;
  231.     gcv.function   = GXcopy;
  232.  
  233.     wtext->gc = XCreateGC( dpy, wtext->core->window,
  234.                            (GCForeground|GCBackground|
  235.                             GCFunction|GCLineWidth),
  236.                            &gcv );
  237.  
  238.     /* set up the regular context */
  239.     gcv.foreground = core->screen_ptr->black_pixel;
  240.     gcv.background = core->screen_ptr->white_pixel;
  241.     gcv.line_width = 1;
  242.     gcv.function   = GXcopy;
  243.  
  244.     wtext->regGC = XCreateGC( dpy, wtext->core->window,
  245.                               (GCForeground|GCBackground|
  246.                    GCFunction|GCLineWidth),
  247.                               &gcv );
  248.  
  249.     /* set up the inverted context */
  250.     gcv.function   = GXcopyInverted;
  251.  
  252.     wtext->invGC = XCreateGC( dpy, wtext->core->window,
  253.                               (GCForeground|GCBackground|
  254.                                GCFunction|GCLineWidth),
  255.                               &gcv );
  256.  
  257.     /* and set the background! */
  258.     XSetWindowBackground( dpy, wtext->core->window, gcv.background );
  259.     }
  260.   
  261.   /* Figure out the y-offset... */
  262.   wtext->yOffset = (height - WMFontHeight(wtext->font))/2;
  263.   wtext->xOffset = wtext->yOffset;
  264.  
  265.   wtext->canceled     = False;
  266.   wtext->done         = False;     /* becomes True when the user    *
  267.                                   * hits "Return" key             */
  268.  
  269.   XMapRaised(dpy, wtext->core->window);
  270.          
  271.   LEAVE("wTextCreate");
  272.   
  273.   return wtext;
  274.   }
  275.  
  276. /********************************************************************\
  277.  * wTextDestroy                                                     *
  278.  *                                                                  *
  279.  * Args:   wtext  - the text field                                  *
  280.  * Return:                                                          *
  281.  * Global: dpy    - the display                                     *
  282. \********************************************************************/
  283. void
  284. wTextDestroy( WTextInput *wtext )
  285.   {
  286.   ENTER("wTextDestroy")
  287.   
  288. #if 0
  289.   if (wtext->magic)
  290.       wDeleteTimerHandler(wtext->magic);
  291.   wtext->magic = NULL;
  292. #endif
  293.   XFreeGC( dpy, wtext->gc );
  294.   XFreeGC( dpy, wtext->regGC );
  295.   XFreeGC( dpy, wtext->invGC );
  296.   free( wtext->text.txt );
  297.   wCoreDestroy( wtext->core );
  298.   free( wtext );
  299.     
  300.   LEAVE("wTextDestroy");
  301.   }
  302.  
  303.  
  304. /* The text-field consists of a frame drawn around the outside,
  305.  * and a textbox inside.  The space between the frame and the
  306.  * text-box is the xOffset,yOffset.  When the text needs refreshing,
  307.  * we only have to redraw the part inside the text-box, and we can
  308.  * leave the frame.  If we get an expose event, or for some reason
  309.  * need to redraw the frame, wTextPaint will redraw the frame, and
  310.  * then call wTextRefresh to redraw the text-box */
  311.  
  312.  
  313. /********************************************************************\
  314.  * textRefresh                                                     *
  315.  *   Redraw the text field.  Call this after messing with the text  *
  316.  *   field.  wTextRefresh re-draws the inside of the text field. If *
  317.  *   the frame-area of the text-field needs redrawing, call         *
  318.  *   wTextPaint()                                                   *
  319.  *                                                                  *
  320.  * Args:   wtext  - the text field                                  *
  321.  * Return: none                                                     *
  322.  * Global: dpy    - the display                                     *
  323. \********************************************************************/
  324. static void
  325. textRefresh( WTextInput *wtext )
  326.   {
  327.   int  x1,x2,y1,y2;
  328.   char *ptr = wtext->text.txt;
  329.   
  330.   /* x1,y1 is the upper left corner of the text box */
  331.   x1 = wtext->xOffset;
  332.   y1 = wtext->yOffset;
  333.   /* x2,y2 is the lower right corner of the text box */
  334.   x2 = wtext->core->width - wtext->xOffset;
  335.   y2 = wtext->core->height - wtext->yOffset;
  336.  
  337.   /* Fill in the text field.  Use the invGC to draw the rectangle, 
  338.    * becuase then it will be the background color */
  339.   XFillRectangle( dpy, wtext->core->window, wtext->invGC,
  340.                 x1, y1, x2-x1, y2-y1 );
  341.  
  342.   /* Draw the text normally */
  343.   WMDrawString(wtext->core->screen_ptr->wmscreen, wtext->core->window, 
  344.            wtext->regGC, wtext->font, x1, y1, ptr, wtext->text.length);
  345.  
  346.   /* Draw the selected text */
  347.   if( wtext->text.startPos != wtext->text.endPos )
  348.     {
  349.     int sp,ep;
  350.     /* we need sp < ep */
  351.     if( wtext->text.startPos > wtext->text.endPos )
  352.       {
  353.       sp = wtext->text.endPos;
  354.       ep = wtext->text.startPos;
  355.       }
  356.     else
  357.       {
  358.       sp = wtext->text.startPos;
  359.       ep = wtext->text.endPos;
  360.       }
  361.     
  362.     /* x1,y1 is now the upper-left of the selected area */
  363.     x1 += WMWidthOfString( wtext->font, ptr, sp );
  364.     /* and x2,y2 is the lower-right of the selected area */
  365.     ptr += sp * sizeof(char);
  366.     x2 = x1 + WMWidthOfString( wtext->font, ptr, (ep - sp) );
  367.     /* Fill in the area  where the selected text will go:     *
  368.      * use the regGC to draw the rectangle, becuase then it   *
  369.      * will be the color of the non-selected text             */
  370.     XFillRectangle( dpy, wtext->core->window, wtext->regGC,
  371.                   x1, y1, x2-x1, y2-y1 );
  372.     
  373.     /* Draw the selected text... use invGC so it will be the
  374.      * opposite color as the filled rectangle */
  375.     WMDrawString(wtext->core->screen_ptr->wmscreen, wtext->core->window, 
  376.          wtext->invGC, wtext->font, x1, y1, ptr, (ep - sp));
  377.     }
  378.   
  379.   /* And draw a quick little line for the cursor position */
  380.   x1 = WMWidthOfString( wtext->font, wtext->text.txt, wtext->text.endPos )
  381.        + wtext->xOffset;
  382.   XDrawLine( dpy, wtext->core->window, wtext->regGC, x1, 2, x1, 
  383.          wtext->core->height - 3 );
  384.   }
  385.  
  386.  
  387. /********************************************************************\
  388.  * wTextPaint                                                       *
  389.  *                                                                  *
  390.  * Args:   wtext  - the text field                                  *
  391.  * Return:                                                          *
  392.  * Global: dpy    - the display                                     *
  393. \********************************************************************/
  394. void
  395. wTextPaint( WTextInput *wtext )
  396.   {
  397.   ENTER("wTextPaint");
  398.  
  399.   /* refresh */
  400.   textRefresh( wtext );
  401.  
  402.   /* Draw box */
  403.   XDrawRectangle(dpy, wtext->core->window, wtext->gc, 0, 0,
  404.          wtext->core->width-1, wtext->core->height-1);
  405.  
  406.   LEAVE("wTextPaint");
  407.   }
  408.  
  409.  
  410. /********************************************************************\
  411.  * wTextGetText                                                     *
  412.  *   return the string in the text field wText.  DO NOT FREE THE    *
  413.  *   RETURNED STRING!                                               *
  414.  *                                                                  *
  415.  * Args:   wtext  - the text field                                  *
  416.  * Return: the text in the text field (NULL terminated)             *
  417.  * Global:                                                          *
  418. \********************************************************************/
  419. char *
  420. wTextGetText( WTextInput *wtext )
  421.   {
  422.      if (!wtext->canceled)
  423.       return wtext->text.txt;
  424.       else
  425.       return NULL;
  426.   }
  427.  
  428. /********************************************************************\
  429.  * wTextPutText                                                     *
  430.  *   Put the string txt in the text field wText.  The text field    *
  431.  *   needs to be explicitly refreshed after wTextPutText by calling *
  432.  *   wTextRefresh().                                                *
  433.  *   The string txt is copied                                       *
  434.  *                                                                  *
  435.  * Args:   wtext  - the text field                                  *
  436.  *         txt    - the new text string... freed by the text field! *
  437.  * Return: none                                                     *
  438.  * Global:                                                          *
  439. \********************************************************************/
  440. void
  441. wTextPutText( WTextInput *wtext, char *txt )
  442.   {
  443.   int length = strlen(txt);
  444.   
  445.   /* no memory leaks!  free the old txt */
  446.   if( wtext->text.txt != NULL )
  447.     free( wtext->text.txt );
  448.   
  449.   wtext->text.txt = (char *)wmalloc((length+1)*sizeof(char));
  450.   strcpy(wtext->text.txt, txt );
  451.   wtext->text.length   = length;
  452.   /* By default No text is selected, and the cursor is at the end */
  453.   wtext->text.startPos = length;
  454.   wtext->text.endPos   = length;
  455.   }
  456.  
  457. /********************************************************************\
  458.  * textInsert                                                      *
  459.  *   Insert some text at the cursor.  (if startPos != endPos,       *
  460.  *   replace the selected text, otherwise insert)                   *
  461.  *   The string txt is copied.                                      *
  462.  *                                                                  *
  463.  * Args:   wText  - the text field                                  *
  464.  *         txt    - the new text string... freed by the text field! *
  465.  * Return: none                                                     *
  466.  * Global:                                                          *
  467. \********************************************************************/
  468. static void
  469. textInsert( WTextInput *wtext, char *txt )
  470.   {
  471.   char *newTxt;
  472.   int  newLen, txtLen, i,j;
  473.   int  sp,ep;
  474.   
  475.   /* we need sp < ep */
  476.   if( wtext->text.startPos > wtext->text.endPos )
  477.     {
  478.     sp = wtext->text.endPos;
  479.     ep = wtext->text.startPos;
  480.     }
  481.   else
  482.     {
  483.     sp = wtext->text.startPos;
  484.     ep = wtext->text.endPos;
  485.     }
  486.   
  487.   txtLen = strlen(txt);
  488.   newLen = wtext->text.length + txtLen - (ep - sp) + 1;
  489.   
  490.   newTxt = (char *)malloc(newLen*sizeof(char));
  491.   
  492.   /* copy the old text up to sp */
  493.   for( i=0; i<sp; i++ )
  494.     newTxt[i] = wtext->text.txt[i];
  495.   
  496.   /* insert new text */
  497.   for( j=0; j<txtLen; j++,i++ )
  498.     newTxt[i] = txt[j];
  499.   
  500.   /* copy old text after ep */
  501.   for( j=ep; j<wtext->text.length; j++,i++ )
  502.     newTxt[i] = wtext->text.txt[j];
  503.   
  504.   newTxt[i] = '\0';
  505.   
  506.   /* By default No text is selected, and the cursor is at the end
  507.    * of inserted text */
  508.   wtext->text.startPos = sp+txtLen;
  509.   wtext->text.endPos   = sp+txtLen;
  510.   
  511.   free(wtext->text.txt);
  512.   wtext->text.txt    = newTxt;
  513.   wtext->text.length = newLen-1;
  514.   }
  515.  
  516. /********************************************************************\
  517.  * wTextSelect                                                      *
  518.  *   Select some text.  If start == end, then the cursor is moved   *
  519.  *   to that position.  If end == -1, then the text from start to   *
  520.  *   the end of the text entered in the text field is selected.     *
  521.  *   The text field is not automatically re-drawn!  You must call   *
  522.  *   wTextRefresh to re-draw the text field.                        *
  523.  *                                                                  *
  524.  * Args:   wtext  - the text field                                  *
  525.  *         start  - the beginning of the selected text              *
  526.  *         end    - the end of the selected text                    *
  527.  * Return: none                                                     *
  528.  * Global:                                                          *
  529. \********************************************************************/
  530. void
  531. wTextSelect( WTextInput *wtext, int start, int end )
  532.   {
  533.   if( end == -1 )
  534.     wtext->text.endPos = wtext->text.length;
  535.   else
  536.     wtext->text.endPos = end;
  537.   wtext->text.startPos = start;
  538.   }
  539.  
  540. #if 0
  541. static void
  542. blink(void *data)
  543. {
  544.     int x;
  545.     WTextInput *wtext = (WTextInput*)data;
  546.     GC gc;
  547.     
  548.   /* And draw a quick little line for the cursor position */
  549.     if (wtext->blink_on) {
  550.     gc = wtext->regGC;
  551.     wtext->blink_on = 0;
  552.     } else {
  553.     gc = wtext->invGC;
  554.     wtext->blink_on = 1;
  555.     }
  556.     x = WMWidthOfString( wtext->font, wtext->text.txt, wtext->text.endPos )
  557.     + wtext->xOffset;
  558.     XDrawLine( dpy, wtext->core->window, gc, x, 2, x, wtext->core->height-3);
  559.  
  560.     if (wtext->blinking)
  561.     wtext->magic = wAddTimerHandler(CURSOR_BLINK_RATE, blink, data);
  562. }
  563. #endif
  564.  
  565. /********************************************************************\
  566.  * textEventHandler -- handles and dispatches all the events that   *
  567.  *   the text field class supports                                  *
  568.  *                                                                  *
  569.  * Args:   desc - all we need to know about this object             *
  570.  * Return: none                                                     *
  571.  * Global:                                                          *
  572. \********************************************************************/
  573. static void
  574. textEventHandler( WObjDescriptor *desc, XEvent *event )
  575.   {
  576.   WTextInput *wtext  = desc->parent;
  577.   int   handled = False;      /* has the event been handled */
  578.  
  579.   switch( event->type )
  580.     {
  581.     case MotionNotify:
  582.       /* If the button isn't down, we don't care about the
  583.        * event, but otherwise we want to adjust the selected
  584.        * text so we can wTextRefresh() */
  585.       if( event->xmotion.state & (Button1Mask|Button3Mask|Button2Mask) )
  586.       {
  587.       DEBUG("MotionNotify");
  588.       handled = True;
  589.       wtext->text.endPos = textXtoPos( wtext, event->xmotion.x );
  590.       }
  591.       break;
  592.  
  593.     case ButtonPress:
  594.       DEBUG("ButtonPress");
  595.       handled = True;
  596.       wtext->text.startPos = textXtoPos( wtext, event->xbutton.x );
  597.       wtext->text.endPos   = wtext->text.startPos;
  598.       break;
  599.  
  600.     case ButtonRelease:
  601.       DEBUG("ButtonRelease");
  602.       handled = True;
  603.       wtext->text.endPos = textXtoPos( wtext, event->xbutton.x );
  604.       break;
  605.  
  606.     case KeyPress:
  607.       DEBUG("KeyPress");
  608.       handled = handleKeyPress( wtext, &event->xkey );
  609.       break;
  610.  
  611.     case EnterNotify:
  612.       DEBUG("EnterNotify");
  613.       handled = True;
  614. #if 0
  615.       if (!wtext->magic) 
  616.     {
  617.     wtext->magic = wAddTimerHandler(CURSOR_BLINK_RATE, blink, wtext);
  618.         wtext->blink_on = !wtext->blink_on;
  619.         blink(wtext);
  620.         wtext->blinking = 1;
  621.         }
  622. #endif
  623.       break;
  624.  
  625.     case LeaveNotify:
  626.       DEBUG("LeaveNotify");
  627.       handled = True;
  628. #if 0
  629.       wtext->blinking = 0;
  630.       if (wtext->blink_on)
  631.         blink(wtext);
  632.       if (wtext->magic)
  633.         wDeleteTimerHandler(wtext->magic);
  634.       wtext->magic = NULL;
  635. #endif
  636.       break;
  637.  
  638.     default:
  639.       break;
  640.     }
  641.   
  642.   if( handled )
  643.     textRefresh(wtext);
  644.   else
  645.     WMHandleEvent(event);
  646.   
  647.   return;
  648.   }
  649.  
  650.  
  651. static void
  652. handleExpose(WObjDescriptor *desc, XEvent *event)
  653. {
  654.     wTextPaint(desc->parent);
  655. }
  656.  
  657.